home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Programming / SWI / source / src / pl-atom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-17  |  8.1 KB  |  417 lines

  1. /*  $Id: pl-atom.c,v 1.24 1997/10/17 16:35:37 jan Exp $
  2.  
  3.     Copyright (c) 1990 Jan Wielemaker. All rights reserved.
  4.     See ../LICENCE to find out about your rights.
  5.     jan@swi.psy.uva.nl
  6.  
  7.     Purpose: atom management
  8. */
  9.  
  10. /*#define O_DEBUG 1*/
  11. #include "pl-incl.h"
  12. #include "pl-ctype.h"
  13.  
  14. static void    rehashAtoms();
  15.  
  16. #define atom_buckets GD->atoms.buckets
  17. #define atom_locked  GD->atoms.locked
  18. #define atomTable    GD->atoms.table
  19.  
  20. #define lockAtoms() { atom_locked++; }
  21. #define unlockAtoms() if ( --atom_locked == 0 && \
  22.                atom_buckets * 2 < GD->statistics.atoms ) \
  23.             rehashAtoms()
  24.  
  25. #if O_DEBUG
  26. #define lookups GD->atoms.lookups
  27. #define    cmps    GD->atoms.cmps
  28. #endif
  29.  
  30.          /*******************************
  31.          *      BUILT-IN ATOM TABLE    *
  32.          *******************************/
  33.  
  34. #define ATOM(s) s
  35.  
  36. typedef const char * ccharp;
  37. static const ccharp atoms[] = {
  38. #include "pl-atom.ic"
  39.   ATOM((char *)NULL)
  40. };
  41. #undef ATOM
  42.  
  43. static void
  44. registerAtom(Atom a)
  45. { int n = entriesBuffer(&atom_array, Atom);
  46.     
  47.   a->atom = (n<<LMASK_BITS)|TAG_ATOM;
  48.  
  49.   addBuffer(&atom_array, a, Atom);
  50. }
  51.  
  52.  
  53.          /*******************************
  54.          *      GENERAL LOOKUP    *
  55.          *******************************/
  56.  
  57. word
  58. lookupAtom(const char *s)
  59. { int v0 = unboundStringHashValue(s);
  60.   int v = v0 & (atom_buckets-1);
  61.   Atom a;
  62.  
  63.   DEBUG(0, lookups++);
  64.  
  65.   for(a = atomTable[v]; a && !isTableRef(a); a = a->next)
  66.   { DEBUG(0, cmps++);
  67.     if (streq(s, a->name) )
  68.       return a->atom;
  69.   }
  70.   a = (Atom)allocHeap(sizeof(struct atom));
  71.   a->next       = atomTable[v];
  72. #ifdef O_HASHTERM
  73.   a->hash_value = v0;
  74. #endif
  75.   a->name       = store_string(s);
  76.   atomTable[v]  = a;
  77.   registerAtom(a);
  78.   GD->statistics.atoms++;
  79.  
  80.   if ( atom_buckets * 2 < GD->statistics.atoms && !atom_locked )
  81.     rehashAtoms();
  82.  
  83.   return a->atom;
  84. }
  85.  
  86.  
  87.          /*******************************
  88.          *        REHASH TABLE    *
  89.          *******************************/
  90.  
  91. static void
  92. makeAtomRefPointers()
  93. { Atom *a;
  94.   int n;
  95.  
  96.   for(n=0, a=atomTable; n < (atom_buckets-1); n++, a++)
  97.     *a = makeTableRef(a+1);
  98.   *a = NULL;
  99. }
  100.  
  101.  
  102. static void
  103. rehashAtoms()
  104. { Atom *oldtab   = atomTable;
  105.   int   oldbucks = atom_buckets;
  106.   Atom a, n;
  107.  
  108.   startCritical;
  109.   atom_buckets *= 2;
  110.   atomTable = allocHeap(atom_buckets * sizeof(Atom));
  111.   makeAtomRefPointers();
  112.   
  113.   DEBUG(0, Sdprintf("rehashing atoms (%d --> %d)\n", oldbucks, atom_buckets));
  114.  
  115.   for(a=oldtab[0]; a; a = n)
  116.   { int v;
  117.  
  118.     while(isTableRef(a) )
  119.     { a = unTableRef(Atom, a);
  120.       if ( a == NULL )
  121.     goto out;
  122.     }
  123.     n = a->next;
  124.     v = a->hash_value & (atom_buckets-1);
  125.     a->next = atomTable[v];
  126.     atomTable[v] = a;
  127.   }
  128.  
  129. out:
  130.   freeHeap(oldtab, oldbucks * sizeof(Atom));
  131.   endCritical;
  132. }
  133.  
  134.  
  135. word
  136. pl_atom_hashstat(term_t idx, term_t n)
  137. { int i, m;
  138.   Atom a;
  139.   
  140.   if ( !PL_get_integer(idx, &i) || i < 0 || i >= atom_buckets )
  141.     fail;
  142.   for(m = 0, a = atomTable[i]; a && !isTableRef(a); a = a->next)
  143.     m++;
  144.  
  145.   return PL_unify_integer(n, m);
  146. }
  147.  
  148. /* Note that the char * of the atoms is copied to the data segment.  This
  149.    is done because some functions temporary change the char string associated
  150.    with an atom (pl_concat_atom()) and GCC puts char constants in the text
  151.    segment.  Is this still true?
  152. */
  153.  
  154.  
  155. static void
  156. registerBuiltinAtoms()
  157. { int size = sizeof(atoms)/sizeof(char *) - 1;
  158.   Atom a = allocHeap(size * sizeof(struct atom));
  159.   const ccharp *s;
  160.  
  161.   GD->statistics.atoms = size;
  162.  
  163.   for(s = atoms; *s; s++, a++)
  164.   { int v0 = unboundStringHashValue(*s);
  165.     int v = v0 & (atom_buckets-1);
  166.  
  167.     a->name       = (char *)*s;
  168. #ifdef O_HASHTERM
  169.     a->hash_value = v0;
  170. #endif
  171.     a->next       = atomTable[v];
  172.     atomTable[v]  = a;
  173.     registerAtom(a);
  174.   }
  175. }
  176.  
  177.  
  178. #if O_DEBUG
  179. static void
  180. exitAtoms(int status, void *arg)
  181. { Sdprintf("hashstat: %d lookupAtom() calls used %d strcmp() calls\n",
  182.        lookups, cmps);
  183. }
  184. #endif
  185.  
  186.  
  187. void
  188. initAtoms(void)
  189. { atom_buckets = ATOMHASHSIZE;
  190.   atomTable = allocHeap(atom_buckets * sizeof(Atom));
  191.   makeAtomRefPointers();
  192.  
  193.   initBuffer(&atom_array);
  194.   registerBuiltinAtoms();
  195.  
  196.   DEBUG(0, PL_on_halt(exitAtoms, NULL));
  197. }
  198.  
  199.  
  200. word
  201. pl_current_atom(term_t a, word h)
  202. { Atom atom;
  203.  
  204.   switch( ForeignControl(h) )
  205.   { case FRG_FIRST_CALL:
  206.       if ( PL_is_atom(a) )      succeed;
  207.       if ( !PL_is_variable(a) ) fail;
  208.  
  209.       atom = atomTable[0];
  210.       lockAtoms();
  211.       break;
  212.     case FRG_REDO:
  213.       atom = ForeignContextPtr(h);
  214.       break;
  215.     case FRG_CUTTED:
  216.     default:
  217.       unlockAtoms();
  218.       succeed;
  219.   }
  220.  
  221.   while(atom && isTableRef(atom) )
  222.     atom = unTableRef(Atom, atom);
  223.  
  224.   if ( atom )
  225.   { PL_unify_atom(a, atom->atom);
  226.  
  227.     return_next_table(Atom, atom, unlockAtoms());
  228.   }
  229.  
  230.   unlockAtoms();
  231.   fail;
  232. }
  233.  
  234.          /*******************************
  235.          *     ATOM COMPLETION    *
  236.          *******************************/
  237.  
  238. #define ALT_SIZ 80        /* maximum length of one alternative */
  239. #define ALT_MAX 256        /* maximum number of alternatives */
  240. #define stringMatch(m)    ((m)->name->name)
  241.  
  242. typedef struct match
  243. { Atom    name;
  244.   int    length;
  245. } *Match;
  246.  
  247.  
  248. static bool
  249. allAlpha(register char *s)
  250. { for( ; *s; s++)
  251.    if ( !isAlpha(*s) )
  252.      fail;
  253.  
  254.   succeed;
  255. }
  256.  
  257.  
  258. static int
  259. extendAtom(char *prefix, bool *unique, char *common)
  260. { Atom a = atomTable[0];
  261.   bool first = TRUE;
  262.   int lp = (int) strlen(prefix);
  263.  
  264.   *unique = TRUE;
  265.  
  266.   for(; a; a = a->next)
  267.   { while( isTableRef(a) )
  268.     { a = unTableRef(Atom, a);
  269.       if ( !a )
  270.     goto out;
  271.     }
  272.     if ( strprefix(a->name, prefix) )
  273.     { if ( strlen(a->name) >= LINESIZ )
  274.     continue;
  275.       if ( first == TRUE )
  276.       { strcpy(common, a->name+lp);
  277.     first = FALSE;
  278.       } else
  279.       { char *s = common;
  280.     char *q = a->name+lp;
  281.     while( *s && *s == *q )
  282.       s++, q++;
  283.     *s = EOS;
  284.     *unique = FALSE;
  285.       }
  286.     }
  287.   }
  288.  
  289. out:
  290.   return !first;
  291. }
  292.  
  293.  
  294. word
  295. pl_complete_atom(term_t prefix, term_t common, term_t unique)
  296. { char *p;
  297.   bool u;
  298.   char buf[LINESIZ];
  299.   char cmm[LINESIZ];
  300.     
  301.   if ( !PL_get_chars(prefix, &p, CVT_ALL) )
  302.     return warning("$complete_atom/3: instanstiation fault");
  303.   strcpy(buf, p);
  304.  
  305.   if ( extendAtom(p, &u, cmm) )
  306.   { strcat(buf, cmm);
  307.     if ( PL_unify_list_chars(common, buf) &&
  308.      PL_unify_atom(unique, u ? ATOM_unique : ATOM_not_unique) )
  309.       succeed;
  310.   }
  311.  
  312.   fail;
  313. }
  314.  
  315.  
  316. static int
  317. compareMatch(const void *m1, const void *m2)
  318. { return strcmp(stringMatch((Match)m1), stringMatch((Match)m2));
  319. }
  320.  
  321.  
  322. static bool
  323. extend_alternatives(char *prefix, struct match *altv, int *altn)
  324. { Atom a = atomTable[0];
  325.   char *as;
  326.   int l;
  327.  
  328.   *altn = 0;
  329.   for(; a; a=a->next)
  330.   { while( a && isTableRef(a) )
  331.       a = unTableRef(Atom, a);
  332.     if ( a == (Atom) NULL )
  333.       break;
  334.     
  335.     as = a->name;
  336.     if ( strprefix(as, prefix) &&
  337.      allAlpha(as) &&
  338.      (l = (int)strlen(as)) < ALT_SIZ )
  339.     { Match m = &altv[(*altn)++];
  340.       m->name = a;
  341.       m->length = l;
  342.       if ( *altn > ALT_MAX )
  343.     break;
  344.     }
  345.   }
  346.   
  347.   qsort(altv, *altn, sizeof(struct match), compareMatch);
  348.  
  349.   succeed;
  350. }
  351.  
  352.  
  353. word
  354. pl_atom_completions(term_t prefix, term_t alternatives)
  355. { char *p;
  356.   char buf[LINESIZ];
  357.   struct match altv[ALT_MAX];
  358.   int altn;
  359.   int i;
  360.   term_t alts = PL_copy_term_ref(alternatives);
  361.   term_t head = PL_new_term_ref();
  362.  
  363.   if ( !PL_get_chars(prefix, &p, CVT_ALL) )
  364.     return warning("$atom_completions/2: instanstiation fault");
  365.   strcpy(buf, p);
  366.  
  367.   extend_alternatives(buf, altv, &altn);
  368.   
  369.   for(i=0; i<altn; i++)
  370.   { if ( !PL_unify_list(alts, head, alts) ||
  371.      !PL_unify_atom(head, altv[i].name->atom) )
  372.       fail;
  373.   }
  374.  
  375.   return PL_unify_nil(alts);
  376.  
  377.  
  378. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  379. Completeness generation for the GNU readline library. This function uses
  380. a state variable to indicate  the   generator  should maintain/reset its
  381. state. Horrible! We use the thread-local   structure to store the state,
  382. so multiple Prolog threads can use this routine.
  383. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  384.  
  385. char *
  386. PL_atom_generator(char *prefix, int state)
  387. { Atom a;
  388.  
  389.   if ( !state )
  390.     a = atomTable[0];
  391.   else
  392.     a = LD->atoms.generator;
  393.  
  394.   for(; a; a=a->next)
  395.   { char *as;
  396.     int l;
  397.  
  398.     while( isTableRef(a) )
  399.     { a = unTableRef(Atom, a);
  400.       if ( !a )
  401.     return NULL;
  402.     }
  403.     
  404.     as = a->name;
  405.     if ( strprefix(as, prefix) &&
  406.      allAlpha(as) &&
  407.      (l = strlen(as)) < ALT_SIZ )
  408.     { LD->atoms.generator = a->next;
  409.       return as;
  410.     }
  411.   }
  412.  
  413.   return NULL;
  414. }
  415.  
  416.